module Mesh3D_m
use MeshCDS_m
type, extends(AMesh) :: mesh3D_t
    type(Node3D), pointer :: nodes(:)
contains
    procedure :: translate => translate3D
    procedure :: scale => scale3D
    procedure :: rotateX => rotateX3D
    procedure :: rotateY => rotateY3D
    procedure :: rotateZ => rotateZ3D
    procedure :: transform => transform3D
end type
private :: translate3D, scale3D, rotateX3D, rotateY3D, rotateZ3D, transform3D
contains
    
subroutine translate3D(this, tx, ty, tz)
    implicit none
	class(mesh3D_t), intent(inout) :: this
	real*8, intent(in) :: tx, ty, tz
	
    real*8 :: x, y, z
	integer :: i
	do i = 1, this%nv
	    x = this%nodes(i)%xyz(1)
		y = this%nodes(i)%xyz(2)
		z = this%nodes(i)%xyz(3)
		this%nodes(i)%xyz(1) = x + tx
		this%nodes(i)%xyz(2) = y + ty
		this%nodes(i)%xyz(3) = z + tz
	end do
end subroutine

subroutine scale3D(this, sx, sy, sz)
    implicit none
    class(mesh3D_t), intent(inout) :: this
    real*8, intent(in) :: sx, sy, sz
    integer :: i
    do i = 1, this%nv
        this%nodes(i)%xyz(1) = this%nodes(i)%xyz(1) * sx
    	this%nodes(i)%xyz(2) = this%nodes(i)%xyz(2) * sy
        this%nodes(i)%xyz(3) = this%nodes(i)%xyz(3) * sz
    end do
end subroutine

subroutine rotateX3D(this, theta)
    implicit none
    class(mesh3D_t), intent(inout) :: this
    real*8, intent(in) :: theta

    integer :: i
    real*8 :: y, z
    do i = 1, this%nv
        y = this%nodes(i)%xyz(2)
        z = this%nodes(i)%xyz(3)
        this%nodes(i)%xyz(2) = cos(theta) * y - sin(theta) * z
        this%nodes(i)%xyz(3) = sin(theta) * y + cos(theta) * z
    end do
end subroutine

subroutine rotateY3D(this, theta)
    implicit none
    class(mesh3D_t), intent(inout) :: this
    real*8, intent(in) :: theta

    integer :: i
    real*8 :: x, z
    do i = 1, this%nv
        x = this%nodes(i)%xyz(1)
        z = this%nodes(i)%xyz(3)
        this%nodes(i)%xyz(1) = cos(theta) * x + sin(theta) * z
        this%nodes(i)%xyz(3) = -sin(theta) * x + cos(theta) * z
    end do
end subroutine

subroutine rotateZ3D(this, theta)
    implicit none
    class(mesh3D_t), intent(inout) :: this
    real*8, intent(in) :: theta

    integer :: i
    real*8 :: x, y
    do i = 1, this%nv
        x = this%nodes(i)%xyz(1)
        y = this%nodes(i)%xyz(2)
        this%nodes(i)%xyz(1) = cos(theta) * x - sin(theta) * y
        this%nodes(i)%xyz(2) = sin(theta) * x + cos(theta) * y
    end do
end subroutine

subroutine transform3D(this, u, v, w)
    implicit none
    class(mesh3D_t), intent(inout) :: this
    real*8, external :: u, v, w
    real*8 :: x, y, z
    integer :: i
    do i = 1, this%nv
        x = this%nodes(i)%xyz(1)
        y = this%nodes(i)%xyz(2)
        z = this%nodes(i)%xyz(3)
        this%nodes(i)%xyz(1) = u(x, y, z)
        this%nodes(i)%xyz(2) = v(x, y, z)
        this%nodes(i)%xyz(3) = w(x, y, z)
    end do
end subroutine

end module
